from concurrent.futures import ThreadPoolExecutor
from datetime import datetime, timedelta
import feedparser
from PyQt5.QtCore import Qt, QTimer, QEvent
from PyQt5.QtWidgets import (
    QMainWindow, QWidget, QVBoxLayout, QTextBrowser, QLineEdit,
    QPushButton, QMenu, QAction, QLabel, QSplitter, QStatusBar,
    QMessageBox, QInputDialog, QProgressBar, QSpinBox, QFontComboBox,
    QDialog, QTreeWidgetItemIterator, QActionGroup
)

from rss_reader import RESOURCES_PATH
from rss_reader.database.models import Article, Feed
from rss_reader.feed_worker import FeedUpdater
from rss_reader.icon_manager import IconManager
from rss_reader.database_manager import DataBaseManager
from rss_reader.json_settings import JsonSettings
from rss_reader.logger import logger
from rss_reader.opml import export_feeds_to_opml, import_feeds_from_opml
from rss_reader.ui.views import FeedTreeWidget, ArticleTable
from rss_reader.ui.category_dialog import CategoryManager


class MainWindow(QMainWindow):
    """RSS阅读器主窗口"""

    def __init__(self, session_factory):
        super().__init__()
        self.session_factory = session_factory
        self.session = self.session_factory()
        self.dbm = DataBaseManager(session_factory)
        self.icon_manager = IconManager()  # 新增图标管理器
        logger.info(f"初始化主窗口")
        self.settings = JsonSettings()
        self.setup_ui()
        self.setup_menu()
        self.setup_signals()
        logger.info(f"setup 完成")

        # 初始化其他属性
        self.update_timer = QTimer()
        self.thread_pool = ThreadPoolExecutor(max_workers=4)
        self.articles = None
        self.display_mode = 'summary'  # 默认显示摘要

        # self.load_config()
        self.setup_content_style()

        # 确保搜索框能捕获回车键
        self.search_box.installEventFilter(self)

        # 启动定时更新
        self.start_scheduled_updates()

        self.restore_ui_state()
        logger.debug("主窗口初始化完成")

    def setup_ui(self):
        """初始化UI界面"""
        self.setWindowTitle(f"RSS阅读器")
        self.setMinimumSize(800, 600)

        # 主分割器
        self.main_splitter = QSplitter(Qt.Horizontal)

        # 左侧边栏
        self.sidebar = QWidget()
        sidebar_layout = QVBoxLayout()

        # 搜索框
        self.search_box = QLineEdit()
        self.search_box.setPlaceholderText("搜索文章 (按Enter开始搜索)")
        self.search_box.returnPressed.connect(self.on_search_triggered)  # 回车键信号
        sidebar_layout.addWidget(self.search_box)

        # 订阅树
        self.feed_tree = FeedTreeWidget(self)
        self.feed_tree.load_feeds()
        # self.feed_tree = FeedTreeView(self.user, self.session_factory, self)
        sidebar_layout.addWidget(self.feed_tree, 1)

        # 更新按钮
        logger.debug("add update button")
        self.update_btn = QPushButton("更新订阅")
        sidebar_layout.addWidget(self.update_btn)

        self.sidebar.setLayout(sidebar_layout)

        # 右侧内容区
        layout = self.settings.get_value("layout")
        logger.debug(f"layout:{layout}")
        if layout == "Horizontal":
            self.content_area_spliter = QSplitter(Qt.Horizontal)
        else:
            self.content_area_spliter = QSplitter(Qt.Vertical)

        # 文章列表
        self.article_table = ArticleTable(self)

        # 文章内容
        self.article_content = QTextBrowser()
        self.article_content.setOpenExternalLinks(True)

        self.content_area_spliter.addWidget(self.article_table)
        self.content_area_spliter.addWidget(self.article_content)
        self.content_area_spliter.setSizes([300, 200])

        # 添加分割器
        self.main_splitter.addWidget(self.sidebar)
        self.main_splitter.addWidget(self.content_area_spliter)
        self.main_splitter.setSizes([200, 600])

        self.setCentralWidget(self.main_splitter)

        # 状态栏
        self.status_bar = QStatusBar()
        self.update_progress = QProgressBar()
        self.update_progress.setMaximumWidth(200)
        self.update_progress.hide()
        self.status_bar.addPermanentWidget(self.update_progress)
        self.setStatusBar(self.status_bar)

        # 设置初始状态
        self.status_bar.showMessage(f"欢迎")

    def setup_menu(self):
        """设置菜单栏"""
        menubar = self.menuBar()

        # 文件菜单
        file_menu = menubar.addMenu("文件")

        import_action = QAction("导入OPML", self)
        import_action.triggered.connect(self.import_opml)
        file_menu.addAction(import_action)

        export_action = QAction("导出OPML", self)
        export_action.triggered.connect(self.export_opml)
        file_menu.addAction(export_action)

        file_menu.addSeparator()

        exit_action = QAction("退出", self)
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)

        # 订阅菜单
        feed_menu = menubar.addMenu("订阅")

        add_action = QAction("添加订阅", self)
        add_action.triggered.connect(self.add_feed)
        feed_menu.addAction(add_action)

        refresh_action = QAction("刷新订阅", self)
        refresh_action.triggered.connect(self.update_all_feeds)
        feed_menu.addAction(refresh_action)

        # 分类管理
        manage_categories_action = QAction("分类管理", self)
        manage_categories_action.triggered.connect(self.manage_categories)
        feed_menu.addAction(manage_categories_action)

        # 添加样式菜单
        view_menu = self.menuBar().addMenu("视图")

        style_action = QAction("内容样式设置", self)
        style_action.triggered.connect(self.show_style_settings)
        view_menu.addAction(style_action)

        """添加布局切换菜单"""
        layout_menu = self.menuBar().addMenu("布局")

        # 垂直布局动作
        vertical_action = QAction("垂直布局", self)
        vertical_action.triggered.connect(lambda: self.update_layout("Vertical"))
        vertical_action.setCheckable(True)

        # 水平布局动作
        horizontal_action = QAction("水平布局", self)
        horizontal_action .triggered.connect(lambda: self.update_layout("Horizontal"))
        horizontal_action.setCheckable(True)

        # 添加到菜单
        layout_menu.addAction(vertical_action)
        layout_menu.addAction(horizontal_action)

        # 创建动作组实现单选
        layout_group = QActionGroup(self)
        layout_group.addAction(vertical_action)
        layout_group.addAction(horizontal_action)

        # 恢复上次布局
        layout = self.settings.get_value("layout")
        if layout == "Vertical":
            vertical_action.setChecked(True)
        else:
            horizontal_action.setChecked(True)

        # 添加显示模式菜单
        display_menu = view_menu.addMenu("显示模式")

        summary_action = QAction("仅显示摘要", self)
        summary_action.triggered.connect(lambda: self.set_display_mode('summary'))

        fulltext_action = QAction("显示全文", self)
        fulltext_action.triggered.connect(lambda: self.set_display_mode('full'))

        display_menu.addAction(summary_action)
        display_menu.addAction(fulltext_action)
        # 帮助菜单
        help_menu = menubar.addMenu("帮助")

        about_action = QAction("关于", self)
        about_action.triggered.connect(self.show_about)
        help_menu.addAction(about_action)

        logger.debug("菜单设置完成")

    def setup_signals(self):
        """连接信号与槽"""
        self.feed_tree.itemClicked.connect(self.on_feed_item_clicked)
        # self.feed_tree.clicked.connect(self.on_feed_selected)
        self.feed_tree.customContextMenuRequested.connect(self.show_feed_context_menu)
        self.article_table.selectionModel().currentRowChanged.connect(self.on_article_selected)
        self.update_btn.clicked.connect(self.update_all_feeds)
        # self.search_box.textChanged.connect(self.search_articles)
        self.article_table.itemSelectionChanged.connect(self.on_article_selection_changed)

        logger.debug("信号连接完成")

    def setup_content_style(self):
        """加载内容显示样式"""
        styles_path = RESOURCES_PATH / 'article_styles.qss'
        if styles_path.exists():
            with open(styles_path, 'r', encoding='utf-8') as f:
                self.article_content.setStyleSheet(f.read())
        else:
            # 默认样式
            self.article_content.setStyleSheet("""
                QTextBrowser {
                    font-size: 14px;
                    line-height: 1.6;
                }
            """)

    def show_style_settings(self):
        """显示样式设置对话框"""
        dialog = QDialog(self)
        dialog.setWindowTitle("内容样式设置")

        layout = QVBoxLayout()

        # 字体大小设置
        font_size_label = QLabel("字体大小:")
        self.font_size_spin = QSpinBox()
        self.font_size_spin.setRange(10, 24)
        self.font_size_spin.setValue(self.article_content.font().pixelSize())

        # 字体选择
        font_family_label = QLabel("字体:")
        self.font_combo = QFontComboBox(self)  # 指定 parent 为当前窗口
        self.font_combo.setCurrentFont(self.article_content.font())

        # 保存按钮
        save_btn = QPushButton("保存设置")
        save_btn.clicked.connect(self.save_style_settings)

        layout.addWidget(font_size_label)
        layout.addWidget(self.font_size_spin)
        layout.addWidget(font_family_label)
        layout.addWidget(self.font_combo)
        layout.addWidget(save_btn)

        dialog.setLayout(layout)
        dialog.exec_()

    def save_style_settings(self):
        """保存样式设置"""
        style = f"""
        QTextBrowser {{
            font-family: {self.font_combo.currentFont().family()};
            font-size: {self.font_size_spin.value()}px;
        }}
        """
        self.article_content.setStyleSheet(style)

        # 保存到文件
        styles_path = RESOURCES_PATH / 'article_styles.qss'
        with open(styles_path, 'w', encoding='utf-8') as f:
            f.write(style)

    def set_display_mode(self, mode):
        """设置内容显示模式"""
        self.display_mode = mode  # 'summary' 或 'full'

        # 获取当前选中文章
        current_article = self.get_current_article()
        if current_article:
            self.update_article_content(current_article)
        else:
            logger.debug("没有选中任何文章")

    def update_article_content(self, article):
        """更新文章内容显示（支持全文/摘要切换）"""
        try:
            # 根据显示模式决定内容
            if hasattr(self, 'display_mode') and self.display_mode == 'full':
                content = article.fetch_full_content()
            else:
                content = article.summary

            html = f"""
            <h1>{article.title}</h1>
            <p><small>
                来源: {article.feed.title} | 
                发布时间: {article.published.strftime('%Y-%m-%d %H:%M:%S') if article.published else "未知时间"}
            </small></p>
            <p><a href='{article.url}'>阅读原文</a></p>
            <hr>
            <div>{content or "无内容"}</div>
            """
            self.article_content.setHtml(html)

            # 取消之前的定时器
            self.article_table.mark_read_timer.stop()

            # 如果未读，启动定时器
            if not article.read:
                logger.debug(f"not read")
                delay = self.settings.get_value("mark_read_delay") * 1000
                logger.debug(f"delay:{delay}")
                self.article_table.mark_read_timer.start(delay)
                selected = self.article_table.selectedItems()
                if selected and len(selected) >= 2:  # 确保选中了标题列
                    first_col_item = selected[1]  # 标题列存储了文章对象
                    self.article_table.current_article_row = first_col_item.row()

        except Exception as e:
            logger.error(f"更新文章内容失败: {str(e)}", exc_info=True)

    def get_current_article(self):
        """获取当前选中的文章"""
        try:
            selected = self.article_table.selectedItems()
            if selected and len(selected) >= 2:  # 确保选中了标题列
                return selected[1].data(Qt.UserRole)  # 标题列存储了文章对象
        except Exception as e:
            logger.error(f"获取当前文章失败: {str(e)}")
        return None

    def update_layout(self, layout):
        """根据设置来应用指定布局"""
        self.settings.set_value("layout", layout)

        # 先移除所有部件
        for widget in [self.article_table,
                       self.article_content]:
            widget.setParent(None)

        # 清除旧分割条
        self.content_area_spliter.setParent(None)
        self.content_area_spliter.deleteLater()

        if layout == "Horizontal":
            # 水平布局 (左中右)
            self.content_area_spliter = QSplitter(Qt.Horizontal)
            self.content_area_spliter.addWidget(self.article_table)
            self.content_area_spliter.addWidget(self.article_content)

            self.main_splitter.addWidget(self.content_area_spliter)

            # 设置默认比例
            self.main_splitter.setSizes([200, 600])
            self.content_area_spliter.setSizes([300, 300])

        else:
            # 品字布局
            self.content_area_spliter = QSplitter(Qt.Vertical)
            self.content_area_spliter.addWidget(self.article_table)
            self.content_area_spliter.addWidget(self.article_content)

            self.main_splitter.addWidget(self.content_area_spliter)

            # 设置默认比例
            self.main_splitter.setSizes([200, 600])
            self.content_area_spliter.setSizes([300, 300])

        # 添加到主窗口
        # self.main_window.centralWidget().layout().addWidget(self.main_splitter)


    def eventFilter(self, obj, event):
        """处理特殊键盘事件"""
        if obj == self.search_box and event.type() == QEvent.KeyPress:
            if event.key() in (Qt.Key_Return, Qt.Key_Enter):
                self.on_search_triggered()
                return True
        return super().eventFilter(obj, event)

    def on_feed_item_clicked(self, item, column):
        """处理树视图点击事件"""
        data = item.data(0, Qt.UserRole)
        item_name = item.text(0)
        item_id = data.get('id')
        item_type = data.get('type')
        try:
            if item_type == "today":  # 今日文章
                logger.debug("用户选择今日文章")
                today = datetime.now() - timedelta(hours=24)
                self.articles = self.session.query(Article) \
                    .filter(Article.published >= today) \
                    .order_by(Article.published.desc()).all()
            elif item_type == "unread":  # 未读订阅节点
                logger.debug("用户选择查看未读文章")
                self.articles = self.session.query(Article) \
                    .join(Article.feed) \
                    .filter(Article.read == False) \
                    .order_by(Article.published.desc()).all()
            elif item_type == "starred":  # 收藏文章
                logger.debug("用户选择查看收藏文章")
                self.articles = self.session.query(Article) \
                    .join(Article.feed) \
                    .filter(Article.starred == True) \
                    .order_by(Article.published.desc()).all()
            elif item_type == "feed":  # 具体订阅源
                logger.debug(f"用户选择查看订阅: {item_name} (ID: {item_id})")
                self.articles = self.session.query(Article) \
                    .filter_by(feed_id=item_id) \
                    .order_by(Article.published.desc()) \
                    .all()
            else:
                logger.debug("用户选择查看所有文章")
                # 获取所有文章
                self.articles = self.session.query(Article) \
                    .join(Article.feed) \
                    .order_by(Article.published.desc()) \
                    .all()

            self.article_table.update_articles()
        except Exception as e:
            logger.error(f"选择订阅时出错: {str(e)}", exc_info=True)

    def on_article_selected(self, current, previous):
        """处理文章选择变化"""
        if current.row() >= 0:
            item = self.article_table.item(current.row(), 0)
            article = item.data(Qt.UserRole)
            self.update_article_content(article)

    def on_article_selection_changed(self):
        """当文章选择变化时更新内容"""
        article = self.get_current_article()
        if article:
            self.update_article_content(article)

    def show_feed_context_menu(self, position):
        """显示订阅源的上下文菜单"""
        try:
            item = self.feed_tree.itemAt(position)
            if not item or item.data(0, Qt.UserRole) is None:
                return

            feed_id = item.data(0, Qt.UserRole)
            logger.debug(f"显示订阅上下文菜单 (ID: {feed_id})")

            menu = QMenu()

            update_action = QAction("更新", self)
            update_action.triggered.connect(lambda: self.update_single_feed(feed_id))
            menu.addAction(update_action)

            delete_action = QAction("删除", self)
            delete_action.triggered.connect(lambda: self.delete_feed(item))
            menu.addAction(delete_action)

            menu.exec_(self.feed_tree.viewport().mapToGlobal(position))

        except Exception as e:
            logger.error(f"显示上下文菜单失败: {str(e)}", exc_info=True)

    def add_feed(self):
        """添加新订阅"""
        try:
            logger.info("用户请求添加新订阅")

            url, ok = QInputDialog.getText(
                self,
                "添加订阅",
                "请输入RSS订阅URL:",
                QLineEdit.Normal
            )

            if ok and url:
                # 简单验证URL
                if not url.startswith(('http://', 'https://')):
                    logger.warning(f"无效的URL输入: {url}")
                    QMessageBox.warning(self, "错误", "请输入有效的URL")
                    return

                # 检查是否已存在
                existing = self.session.query(Feed) \
                    .filter_by(url=url) \
                    .first()
                if existing:
                    logger.info(f"订阅已存在: {url}")
                    QMessageBox.information(self, "提示", "该订阅已存在")
                    return

                # 获取分类
                category, ok = QInputDialog.getText(
                    self,
                    "分类",
                    "请输入分类名称:",
                    QLineEdit.Normal,
                    "未分类"
                )

                if not ok:
                    logger.debug("用户取消添加订阅")
                    return

                try:
                    # 尝试解析订阅以获取标题
                    logger.debug(f"尝试解析订阅URL: {url}")
                    parsed = feedparser.parse(url)
                    title = parsed.feed.get('title', '新订阅')
                    icon_url = parsed.feed.get('icon') or parsed.feed.get('image', {}).get('href')

                    feed = Feed(
                        title=title,
                        url=url,
                        icon_url=icon_url,
                        category=category,
                    )
                    self.session.add(feed)
                    self.session.commit()

                    logger.info(f"成功添加新订阅: {title} ({url})")

                    self.feed_tree.load_feeds()
                    QMessageBox.information(self, "成功", "订阅添加成功")

                except Exception as e:
                    self.session.rollback()
                    logger.error(f"添加订阅失败: {str(e)}", exc_info=True)
                    QMessageBox.critical(self, "错误", f"添加订阅失败: {str(e)}")

        except Exception as e:
            logger.error(f"添加订阅过程中出错: {str(e)}", exc_info=True)
            QMessageBox.critical(self, "错误", "添加订阅过程中出错")

    def delete_feed(self, item):
        """删除订阅"""
        try:

            feed_id = item.data(0, Qt.UserRole)
            if not feed_id:
                return

            logger.info(f"用户请求删除订阅 (ID: {feed_id})")

            reply = QMessageBox.question(
                self,
                "确认删除",
                "确定要删除这个订阅吗?相关的文章也将被删除。",
                QMessageBox.Yes | QMessageBox.No
            )

            if reply == QMessageBox.Yes:
                feed = self.session.query(Feed).get(feed_id)
                if feed:
                    self.session.delete(feed)
                    self.session.commit()

                    logger.info(f"成功删除订阅: {feed.title} (ID: {feed_id})")

                    self.load_feeds()
                    # 选择 treeview 的第一个节点
                    if self.feed_tree.model().rowCount() > 0:
                        first_index = self.feed_tree.model().index(0, 0)
                        self.feed_tree.setCurrentIndex(first_index)
                        self.feed_tree.clicked.emit(first_index)

        except Exception as e:
            self.session.rollback()
            logger.error(f"删除订阅失败: {str(e)}", exc_info=True)
            QMessageBox.critical(self, "错误", "删除订阅失败")

    def update_single_feed(self, feed_id):
        """更新单个订阅源时也更新图标"""
        try:
            feed = self.session.query(Feed).get(feed_id)
            if feed:
                # 获取最新图标
                new_icon = self.icon_manager.get_icon(feed)

                # 更新树状图中的图标
                for i in range(self.feed_tree.topLevelItemCount()):
                    category_item = self.feed_tree.topLevelItem(i)
                    for j in range(category_item.childCount()):
                        child = category_item.child(j)
                        if child.data(0, Qt.UserRole) == feed.id:
                            child.setIcon(0, new_icon)
                            break

                # 如果获取到新图标，更新数据库
                if new_icon != self.icon_manager.feed_default_icon and feed.icon_url != new_icon:
                    feed.icon_url = new_icon
                    self.session.commit()

        except Exception as e:
            logger.error(f"更新订阅图标失败: {str(e)}", exc_info=True)

    def update_all_feeds(self):
        """更新所有订阅"""
        try:
            feeds = self.session.query(Feed).all()
            if not feeds:
                logger.info("没有可更新的订阅")
                QMessageBox.information(self, "提示", "没有可更新的订阅")
                return

            feed_ids = [feed.id for feed in feeds]
            logger.info(f"用户请求更新所有订阅 (共 {len(feed_ids)} 个)")

            updater = FeedUpdater(self.session_factory, feed_ids)
            updater.signals.progress.connect(self.on_update_progress)
            updater.signals.finished.connect(self.on_update_finished)
            updater.signals.error.connect(self.on_update_error)

            self.thread_pool.submit(updater.run)
            self.show_progress(len(feed_ids))

        except Exception as e:
            logger.error(f"启动全部订阅更新失败: {str(e)}", exc_info=True)
            QMessageBox.critical(self, "错误", "更新订阅失败")

    def on_update_progress(self, current, total):
        """更新进度"""
        self.update_progress.setMaximum(total)
        self.update_progress.setValue(current)
        self.status_bar.showMessage(f"正在更新: {current}/{total}")

    def on_update_finished(self):
        """更新完成"""
        self.update_progress.hide()
        self.status_bar.showMessage("更新完成", 3000)
        self.feed_tree.load_feeds()

        # 重新加载当前文章列表
        current_item = self.feed_tree.currentItem()
        if current_item:
            self.on_feed_selected(current_item)

        logger.info("所有订阅更新完成")

    def on_update_error(self, error):
        """更新错误"""
        self.update_progress.hide()
        logger.error(f"订阅更新错误: {error}")
        QMessageBox.critical(self, "更新错误", error)

    def show_progress(self, total):
        """显示进度条"""
        self.update_progress.setMaximum(total)
        self.update_progress.setValue(0)
        self.update_progress.show()

    def start_scheduled_updates(self):
        """启动定时更新"""
        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.update_all_feeds)
        self.update_timer.start(3600000)  # 每小时更新一次
        logger.info("定时更新已启动，每小时更新一次")

    def import_opml(self):
        """导入OPML文件"""
        try:
            logger.info("用户请求导入OPML文件")

            count = import_feeds_from_opml(self.session, self)
            if count:
                logger.info(f"成功导入 {count} 个订阅")
                QMessageBox.information(self, "导入成功", f"成功导入 {count} 个订阅")
                self.load_feeds()
            elif count is False:
                logger.warning("OPML导入失败")
                QMessageBox.warning(self, "导入失败", "导入过程中发生错误")

        except Exception as e:
            logger.error(f"导入OPML失败: {str(e)}", exc_info=True)
            QMessageBox.critical(self, "错误", "导入OPML文件失败")

    def export_opml(self):
        """导出OPML文件"""
        try:
            logger.info("用户请求导出OPML文件")

            if export_feeds_to_opml(self.session, self):
                logger.info("订阅导出成功")
                QMessageBox.information(self, "导出成功", "订阅已成功导出")
            else:
                logger.warning("没有订阅可导出或导出失败")
                QMessageBox.warning(self, "导出失败", "没有订阅可导出或导出过程中发生错误")

        except Exception as e:
            logger.error(f"导出OPML失败: {str(e)}", exc_info=True)
            QMessageBox.critical(self, "错误", "导出OPML文件失败")

    def on_search_triggered(self):
        """回车键触发的搜索方法"""
        search_text = self.search_box.text().strip()
        if search_text:
            self.search_articles(search_text)
        else:
            # 清空搜索时恢复显示当前内容
            current_item = self.feed_tree.currentItem()
            if current_item:
                self.on_feed_selected(current_item)

    def search_articles(self, text):
        """执行文章搜索"""
        try:

            search_text = text.strip()
            if not search_text:
                return

            logger.info(f"用户搜索文章: {search_text}")

            # 清空当前选择
            self.article_table.clearSelection()

            # 执行搜索查询
            self.articles = self.session.query(Article) \
                .join(Article.feed) \
                .filter(
                Article.title.contains(search_text) |
                Article.summary.contains(search_text)
            ) \
                .order_by(Article.published.desc()) \
                .all()

            # 更新表格显示
            self.article_table.update_articles()
            logger.info(f"找到 {len(self.articles)} 篇匹配文章")

        except Exception as e:
            logger.error(f"搜索文章失败: {str(e)}", exc_info=True)
            QMessageBox.critical(self, "错误", "搜索文章失败")

    def show_about(self):
        """显示关于对话框"""
        QMessageBox.about(
            self,
            "关于 RSS阅读器",
            "PyQt RSS阅读器\n版本 0.1.0\n\n一个简单的RSS阅读器，支持订阅管理和文章阅读。"
        )
        logger.debug("用户查看关于信息")

    def closeEvent(self, event):
        """关闭窗口时清理资源"""
        logger.info("主窗口关闭，开始清理资源")
        try:
            self.save_ui_state()
            # 停止定时更新
            if hasattr(self, 'update_timer'):
                self.update_timer.stop()
                logger.debug("定时更新已停止")

            # 关闭线程池
            if hasattr(self, 'thread_pool'):
                self.thread_pool.shutdown(wait=False)
                logger.debug("线程池已关闭")

            # 关闭数据库会话
            if hasattr(self, 'session'):
                self.session.close()
                logger.debug("数据库会话已关闭")

            # 移除scoped_session注册
            if hasattr(self, 'session_factory'):
                self.session_factory.remove()
                logger.debug("scoped_session注册已移除")

            logger.info("资源清理完成，应用程序退出")
            event.accept()

        except Exception as e:
            logger.error(f"关闭窗口时出错: {str(e)}", exc_info=True)
            event.accept()

    def save_ui_state(self):
        """保存所有UI状态到JSON"""
        # 主窗口状态
        self.settings.set_bytearray("window.geometry", self.saveGeometry())
        self.settings.set_bytearray("window.state", self.saveState())

        # 分割器状态
        self.settings.set_bytearray(
            "main_splitter.state",
            self.main_splitter.saveState())

        # TreeView状态
        self.feed_tree.save_expanded_state()
        self.settings.set_value("feed_tree.expanded", getattr(self.feed_tree, '_expanded_state', {}))

        # 当前选中项
        selected_id = self.feed_tree.get_selected_feed_id()
        if selected_id:
            self.settings.set_value("feed_tree.selected_feed", selected_id)

        # content size
        self.settings.set_bytearray(
            "content_area_spliter.state",
            self.content_area_spliter.saveState())

    def restore_ui_state(self):
        """从JSON恢复UI状态"""
        # 恢复窗口
        if geometry := self.settings.get_bytearray("window.geometry"):
            self.restoreGeometry(geometry)
        if state := self.settings.get_bytearray("window.state"):
            self.restoreState(state)

        # 恢复分割器
        if splitter_state := self.settings.get_bytearray("main_splitter.state"):
            self.main_splitter.restoreState(splitter_state)

        # 恢复tree展开状态
        if expanded_state := self.settings.get_value("feed_tree.expanded"):
            self.feed_tree._expanded_state = expanded_state
            QTimer.singleShot(100, self.feed_tree.restore_expanded_state)

        # 恢复treeview选中项
        if selected_id := self.settings.get_value("feed_tree.selected_feed"):
            self._select_feed_by_id(selected_id)

        # content area
        if content_area_spliter_state := self.settings.get_bytearray(
                "content_area_spliter.state"):
            self.content_area_spliter.restoreState(content_area_spliter_state)

    def _delayed_restore_treeview(self):
        """延迟恢复TreeView状态"""
        # 展开节点
        if expanded := self.settings.get_value("treeview.expanded", []):
            model = self.tree_view.model()
            for i in expanded:
                if i < model.rowCount():
                    self.tree_view.expand(model.index(i, 0))

    def _select_feed_by_id(self, feed_id):
        """通过ID选中指定的feed"""
        iterator = QTreeWidgetItemIterator(self.feed_tree)
        while iterator.value():
            item = iterator.value()
            data = item.data(0, Qt.UserRole)
            if data and data.get('id') == feed_id:
                # self.feed_tree.setCurrentItem(item)
                self.on_feed_item_clicked(item,0)
                break
            iterator += 1

    def manage_categories(self):
        """打开分类管理对话框"""
        dialog = CategoryManager(self.feed_tree.model(), self)
        dialog.exec_()
        self.feed_tree.model().refresh()
